[ayoung@blog posts]$ cat ./Fuzzing software common challenges and potential solutions.md

Fuzzing software common challenges and potential solutions

[Last modified: 2025-05-13]

fuzz命令行参数

计算需要的总字节数,布尔1bit,浮点数和整型用4/8字节,可变长度字符串用固定大小的数组

首先计算出新块需要的总字节数,取每个参数数据类型长度之和。示例中为50字节。

在输入文件前添加一个50字节的零块,该块内容将逐渐被fuzzer改变。 最后代码中加入代码片段,以便为每个块位置分配一个输入变量。

    unsigned char arguments[50] = {0};
    fread(arguments, 1, 50, inputFile);
    
    randomArg = (arguments[0] >> 7) & 1;
    loopArg = (arguments[0] >> 6) & 1;
    repeatArg = (arguments[0] >> 5) & 1;
    playAndExit = (arguments[0] >> 4) & 1;
    playAndStop = (arguments[0] >> 3) & 1;
	playAndPause = (arguments[0] >> 2) & 1;
	startPaused = (arguments[0] >> 1) & 1;
	playlistAutostart = (arguments[0] >> 0) & 1;
    
    memcpy(&grain-variance, arguments[1], 4);
    memcpy(&grain-period-min, arguments[5], 4);
    memcpy(&grain-period-max, arguments[9], 4);
    
    memcpy(scene-format, arguments[13], 50-13);
    
    //File content starts at inputFile[50]

分割比较

一个例子如下

fuzzer不太可能碰巧得到这个确切的值 如果能将这个比较语句拆分成多个单字节比较语句,且每个比较语句都进行了检测,就会执行第一个嵌套if语句,从而发现新路径,进而向AFL发出信号,表明当前输入应该在进一步fuzz中再次使用。从而让fuzzer发现并通过该条件语句

Laf-intel AFL plugin 插件就是干这个的

可以配置下面环境变量来处理

export AFL_LLVM_LAF_SPLIT_SWITCHES=1
export AFL_LLVM_LAF_TRANSFORM_COMPARES=1
export AFL_LLVM_LAF_SPLIT_COMPARES=1
export AFL_LLVM_LAF_SPLIT_FLOATS=1

提供自定义字典

模块guid

可以为fuzzer提供包含这些常数值的字典

Override:用n个字节替换特定位置,其中n是字典条目的长度。 Insert:将字典条目插入到当前文件位置,强制所有字符下移n个位置并增加文件大小。

可以用脚本或者codeql搜索 eg

import cpp

from StringLiteral l, Call fc
where 	l.getFile().getBaseName() = "ogg.c"
		and (fc.getTarget().getQualifiedName() = "memcmp" or fc.getTarget().getQualifiedName() = "strcmp")
		and fc.getAnArgument() = l
select l.getValueText()

再看另一个例子,查找guid相关所有全局变量

import cpp

from GlobalVariable gb
where gb.getFile().getBaseName() = "libasf_guid.h"
select gb

注意某些情况下需要反转字典条目的字节顺序

可以重构与目标相关语言的语法(xml sql) 不过这种方法实践中似乎不太行

处理checksum

举例ogg媒体容器文件格式指定ogg页头如下

两种策略:

还要对代码修改:

/* Compare */
if(memcmp(chksum,page+22,4)){
/* D’oh. Mismatch! Corrupt page (or miscapture and not a page at all) */
/* replace the computed checksum with the one actually read in */
memcpy(page+22,chksum,4)

注释掉memcmp语句即可避免crc检查

自定义覆盖率

如果不对代码覆盖率施加限制 fuzzer容易选择错误路径 造成效率降低

为解决此问题 afl++包含一个白名单特性,允许指定(在源文件级别)哪些文件应该使用或不使用插桩进行编译 该特性只在使用llvm时可用,要在编译时设置AFL_LLVM_WHITELIST变量,该环境变量指向一个包含所有应该检测的文件名的文件

还可以给每个白名单创建特定字典

reference